﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SequenceAssembler
{
	class LowCoverageRemover
	{
		BackGraph bg;
		public float CoverageThreshold { get; set; }

		public LowCoverageRemover(BackGraph backGraph) {
			bg = backGraph;
			CoverageThreshold = 3;
		}

		public void Remove() {
			long before = bg.CellCount;
			long after = 0;
			SimpleCellMerger merger = new SimpleCellMerger(bg);
			while (before != after)
			{
				Console.WriteLine("Pre remove cell count: {0}", bg.CellCount);
				before = bg.CellCount;
				RemoveOnce();
				merger.Merge();
				after = bg.CellCount;
				Console.WriteLine("Post remove cell count: {0}", bg.CellCount);
			}
		}

		private void RemoveOnce() {
			List<long> celllist = new List<long>(bg.CellList);
			foreach (long id in celllist) {
				SequenceCell cell = bg.LoadCell<SequenceCell>(id);
				if (cell == null) { continue; }
				if (!Low(cell)) { continue; }

				long twinId = bg.TwinId(cell.Id);
				SequenceCell twinCell = bg.LoadCell<SequenceCell>(twinId);
				
				long[] preTwinIds = new long[cell.Arcs.Count];
				for (int i = 0; i < cell.Arcs.Count; ++i) {
					preTwinIds[i] = bg.TwinId(cell.Arcs[i].Destination);
				}
				SequenceCell[] preTwinCells = bg.LoadCells<SequenceCell>(preTwinIds);
				
				long[] preIds = new long[twinCell.Arcs.Count];
				for (int i = 0; i < twinCell.Arcs.Count; ++i) {
					preIds[i] = bg.TwinId(twinCell.Arcs[i].Destination);
				}
				SequenceCell[] preCells = bg.LoadCells<SequenceCell>(preIds);

				FixArcs(preCells, id);
				FixArcs(preTwinCells, twinId);
				bg.SaveCells(preCells);
				bg.SaveCells(preTwinCells);
				bg.DeleteCell(cell);
				bg.DeleteCell(twinCell);
			}
		}

		private void FixArcs(SequenceCell[] cells, long toRemove) {
			foreach (var cell in cells)
			{
				for (int i = 0; i < cell.Arcs.Count; ++i) {
					if (cell.Arcs[i].Destination == toRemove) {
						cell.Arcs.RemoveAt(i--);
					}
				}
			}
		}

		protected bool Low(SequenceCell cell) {
			return cell.Coverage < CoverageThreshold;
		}
	}
}
